jss-api 0.5.8 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/CHANGES.md +55 -7
  2. data/README.md +2 -1
  3. data/bin/cgrouper +1 -1
  4. data/bin/subnet-update +1 -1
  5. data/lib/jss-api.rb +2 -363
  6. data/lib/jss-api/api_connection.rb +78 -15
  7. data/lib/jss-api/api_object.rb +1 -1
  8. data/lib/jss-api/api_object/advanced_search.rb +1 -1
  9. data/lib/jss-api/api_object/advanced_search/advanced_computer_search.rb +1 -1
  10. data/lib/jss-api/api_object/advanced_search/advanced_mobile_device_search.rb +1 -1
  11. data/lib/jss-api/api_object/advanced_search/advanced_user_search.rb +1 -1
  12. data/lib/jss-api/api_object/building.rb +1 -1
  13. data/lib/jss-api/api_object/category.rb +1 -1
  14. data/lib/jss-api/api_object/computer.rb +1 -1
  15. data/lib/jss-api/api_object/creatable.rb +1 -1
  16. data/lib/jss-api/api_object/criteriable.rb +1 -1
  17. data/lib/jss-api/api_object/criteriable/criteria.rb +1 -1
  18. data/lib/jss-api/api_object/criteriable/criterion.rb +1 -1
  19. data/lib/jss-api/api_object/department.rb +1 -1
  20. data/lib/jss-api/api_object/distribution_point.rb +92 -22
  21. data/lib/jss-api/api_object/extendable.rb +1 -1
  22. data/lib/jss-api/api_object/extension_attribute.rb +1 -1
  23. data/lib/jss-api/api_object/extension_attribute/computer_extension_attribute.rb +1 -1
  24. data/lib/jss-api/api_object/extension_attribute/mobile_device_extension_attribute.rb +1 -1
  25. data/lib/jss-api/api_object/extension_attribute/user_extension_attribute.rb +1 -1
  26. data/lib/jss-api/api_object/group.rb +1 -1
  27. data/lib/jss-api/api_object/group/computer_group.rb +1 -1
  28. data/lib/jss-api/api_object/group/mobile_device_group.rb +1 -1
  29. data/lib/jss-api/api_object/group/user_group.rb +1 -1
  30. data/lib/jss-api/api_object/ldap_server.rb +1 -1
  31. data/lib/jss-api/api_object/locatable.rb +1 -1
  32. data/lib/jss-api/api_object/matchable.rb +1 -1
  33. data/lib/jss-api/api_object/mobile_device.rb +1 -1
  34. data/lib/jss-api/api_object/netboot_server.rb +1 -1
  35. data/lib/jss-api/api_object/network_segment.rb +1 -1
  36. data/lib/jss-api/api_object/osx_configuration_profile.rb +1 -1
  37. data/lib/jss-api/api_object/package.rb +117 -64
  38. data/lib/jss-api/api_object/peripheral.rb +1 -1
  39. data/lib/jss-api/api_object/peripheral_type.rb +1 -1
  40. data/lib/jss-api/api_object/policy.rb +1 -1
  41. data/lib/jss-api/api_object/purchasable.rb +1 -1
  42. data/lib/jss-api/api_object/removable_macaddr.rb +1 -1
  43. data/lib/jss-api/api_object/scopable.rb +1 -1
  44. data/lib/jss-api/api_object/scopable/scope.rb +1 -1
  45. data/lib/jss-api/api_object/script.rb +1 -1
  46. data/lib/jss-api/api_object/self_servable.rb +1 -1
  47. data/lib/jss-api/api_object/site.rb +1 -1
  48. data/lib/jss-api/api_object/software_update_server.rb +1 -1
  49. data/lib/jss-api/api_object/updatable.rb +1 -1
  50. data/lib/jss-api/api_object/uploadable.rb +1 -1
  51. data/lib/jss-api/api_object/user.rb +1 -1
  52. data/lib/jss-api/client.rb +22 -21
  53. data/lib/jss-api/compatibility.rb +1 -1
  54. data/lib/jss-api/composer.rb +2 -2
  55. data/lib/jss-api/configuration.rb +1 -1
  56. data/lib/jss-api/db_connection.rb +63 -12
  57. data/lib/jss-api/exceptions.rb +1 -1
  58. data/lib/jss-api/ruby_extensions.rb +1 -1
  59. data/lib/jss-api/ruby_extensions/filetest.rb +1 -1
  60. data/lib/jss-api/ruby_extensions/hash.rb +1 -1
  61. data/lib/jss-api/ruby_extensions/ipaddr.rb +1 -1
  62. data/lib/jss-api/ruby_extensions/pathname.rb +1 -1
  63. data/lib/jss-api/ruby_extensions/string.rb +17 -1
  64. data/lib/jss-api/ruby_extensions/time.rb +1 -1
  65. data/lib/jss-api/server.rb +1 -1
  66. data/lib/jss-api/utility.rb +416 -0
  67. data/lib/jss-api/version.rb +8 -8
  68. metadata +3 -2
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,25 +1,25 @@
1
- ### Copyright 2014 Pixar
2
- ###
1
+ ### Copyright 2016 Pixar
2
+ ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
5
5
  ### compliance with the Apache License and the following modification to it:
6
6
  ### Section 6. Trademarks. is deleted and replaced with:
7
- ###
7
+ ###
8
8
  ### 6. Trademarks. This License does not grant permission to use the trade
9
9
  ### names, trademarks, service marks, or product names of the Licensor
10
10
  ### and its affiliates, except as required to comply with Section 4(c) of
11
11
  ### the License and to reproduce the content of the NOTICE file.
12
- ###
12
+ ###
13
13
  ### You may obtain a copy of the Apache License at
14
- ###
14
+ ###
15
15
  ### http://www.apache.org/licenses/LICENSE-2.0
16
- ###
16
+ ###
17
17
  ### Unless required by applicable law or agreed to in writing, software
18
18
  ### distributed under the Apache License with the above modification is
19
19
  ### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20
20
  ### KIND, either express or implied. See the Apache License for the specific
21
21
  ### language governing permissions and limitations under the Apache License.
22
- ###
22
+ ###
23
23
  ###
24
24
 
25
25
  ###
@@ -86,6 +86,8 @@ module JSS
86
86
  ### The possible values for cpu_type (required_processor) in a JSS package
87
87
  CPU_TYPES = ["None", "x86", "ppc"]
88
88
 
89
+ # TO DO - this is redundant with DEFAULT_PROCESSOR, but both are in use
90
+ # clean them up!
89
91
  ### which is default? there must be one to make a new pkg
90
92
  DEFAULT_CPU_TYPE = "None"
91
93
 
@@ -115,10 +117,10 @@ module JSS
115
117
 
116
118
  ### @return [String] the filename of the .pkg, .mpkg, or .dmg on the Casper server
117
119
  attr_reader :filename
118
-
119
- ### @return [Pathname] the local receipt when this pkg is installed
120
+
121
+ ### @return [Pathname] the local receipt when this pkg is installed
120
122
  attr_reader :receipt
121
-
123
+
122
124
  ### @return [Boolean] does this item 'Fill Existing Users' when jamf installs it?
123
125
  attr_reader :fill_existing_users
124
126
 
@@ -130,16 +132,16 @@ module JSS
130
132
 
131
133
  ### @return [Array<String>] the OS versions this can be installed onto. For all minor versions, the format is 10.5.x
132
134
  attr_reader :os_requirements
133
-
135
+
134
136
  ### @return [String] limit installation to these architectures: 'x86', 'ppc', 'None'
135
137
  attr_reader :required_processor
136
-
138
+
137
139
  ### @return [String] the name of a pkg to install (or "Do Not Install") when this pkg can't be installed
138
140
  attr_reader :switch_with_package
139
141
 
140
142
  ### @return [Boolean] can this item be uninstalled? Some, e.g. OS Updates, can't
141
143
  attr_reader :allow_uninstalled
142
-
144
+
143
145
  ### @return [String] the category of this pkg, stored in the JSS as the id number from the categories table
144
146
  attr_reader :category
145
147
 
@@ -151,16 +153,16 @@ module JSS
151
153
 
152
154
  ### @return [Boolean] only install this pkg if it's available in the commandline softwareupdate.
153
155
  attr_reader :install_if_reported_available
154
-
156
+
155
157
  ### @return [Boolean] should this pkg be installed on the boot volume during imaging
156
158
  attr_reader :boot_volume_required
157
-
159
+
158
160
  ### @return [Integer] Priority to use for deploying or uninstalling the package
159
161
  attr_reader :priority
160
162
 
161
163
  ### @return [Boolean] does this pkg cause a notification to be sent on self-heal?
162
164
  attr_reader :send_notification
163
-
165
+
164
166
 
165
167
  ###
166
168
  ### @see JSS::APIObject#initialize
@@ -173,6 +175,7 @@ module JSS
173
175
  @allow_uninstalled = @init_data[:allow_uninstalled]
174
176
  @boot_volume_required = @init_data[:boot_volume_required]
175
177
  @category = JSS::APIObject.get_name(@init_data[:category])
178
+ @category = nil if @category.to_s.casecmp("No category assigned") == 0
176
179
  @filename = @init_data[:filename] || @init_data[:name]
177
180
  @fill_existing_users = @init_data[:fill_existing_users]
178
181
  @fill_user_template = @init_data[:fill_user_template]
@@ -185,12 +188,12 @@ module JSS
185
188
  @priority = @init_data[:priority] || DEFAULT_PRIORITY
186
189
  @reboot_required = @init_data[:reboot_required]
187
190
  @required_processor = @init_data[:required_processor] || DEFAULT_CPU_TYPE
191
+ @required_processor = nil if @required_processor.to_s.casecmp('none') == 0
188
192
  @send_notification = @init_data[:send_notification]
189
193
  @switch_with_package = @init_data[:switch_with_package] || DO_NOT_INSTALL
190
-
194
+
191
195
  # the receipt is the filename with any .zip extension removed.
192
- @receipt = @filname ? (JSS::Client::RECEIPTS_FOLDER + @filname.to_s.sub(/.zip$/, '')) : nil
193
-
196
+ @receipt = @filename ? (JSS::Client::RECEIPTS_FOLDER + @filename.to_s.sub(/.zip$/, '')) : nil
194
197
  end # init
195
198
 
196
199
 
@@ -478,7 +481,7 @@ module JSS
478
481
  def installed?
479
482
  @receipt.file?
480
483
  end
481
-
484
+
482
485
  ###
483
486
  ### Upload a locally-readable file to the master distribution point.
484
487
  ### If the file is a directory (like a bundle .pk/.mpkg) it will be zipped before
@@ -489,7 +492,7 @@ module JSS
489
492
  ###
490
493
  ### @param local_file_path[String,Pathname] the local path to the file to be uploaded
491
494
  ###
492
- ### @param rw_pw[String,Symbol] the password for the read/write account on the master Distribution Point,
495
+ ### @param rw_pw[String,Symbol] the password for the read/write account on the master Distribution Point,
493
496
  ### or :prompt, or :stdin# where # is the line of stdin containing the password See {JSS::DistributionPoint#mount}
494
497
  ###
495
498
  ### @param unmount[Boolean] whether or not ot unount the distribution point when finished.
@@ -499,7 +502,7 @@ module JSS
499
502
  def upload_master_file (local_file_path, rw_pw, unmount = true)
500
503
 
501
504
  raise JSS::NoSuchItemError, "Please create this package in the JSS before uploading it." unless @in_jss
502
-
505
+
503
506
  mdp = JSS::DistributionPoint.master_distribution_point
504
507
  destination = mdp.mount(rw_pw, :rw) +"#{DIST_POINT_PKGS_FOLDER}/#{@filename}"
505
508
 
@@ -534,11 +537,11 @@ module JSS
534
537
  local_path = zipfile
535
538
 
536
539
  self.filename = zipfile.basename.to_s
537
-
540
+
538
541
  end # if directory
539
542
  self.update
540
543
  FileUtils.copy_entry local_path, destination
541
-
544
+
542
545
  mdp.unmount if unmount
543
546
  end # upload
544
547
 
@@ -569,21 +572,23 @@ module JSS
569
572
  end # delete master file
570
573
 
571
574
 
575
+ ### Install this package via the jamf binary 'install' command from the
576
+ ### distribution point for this machine.
577
+ ### See {JSS::DistributionPoint.my_distribution_point}
572
578
  ###
573
579
  ### @note This code must be run as root to install packages
574
580
  ###
575
- ### Causes the pkg/dmg to be installed via the jamf binary 'install' command from the
576
- ### distribution point for this machine. See {JSS::DistributionPoint.my_distribution_point}
577
- ###
578
- ### The read-only or http passwd for the dist. point must be provided, except for
579
- ### non-authenticated http downloads)
581
+ ### The read-only or http passwd for the dist. point must be provided,
582
+ ### except for non-authenticated http downloads)
580
583
  ###
581
584
  ### @param args[Hash] the arguments for installation
582
585
  ###
583
- ### @option args :ro_pw[String] the read-only or http password for the distribution point for the
584
- ### local machine (http will be used if available, and may not need a pw)
586
+ ### @option args :ro_pw[String] the read-only or http password for the
587
+ ### distribution point for the local machine
588
+ ### (http will be used if available, and may not need a pw)
585
589
  ###
586
- ### @option args :target[String,Pathname] The drive on which to install the package, defaults to '/'
590
+ ### @option args :target[String,Pathname] The drive on which to install
591
+ ### the package, defaults to '/'
587
592
  ###
588
593
  ### @option args :verbose [Boolean] be verbose to stdout, defaults to false
589
594
  ###
@@ -591,14 +596,21 @@ module JSS
591
596
  ###
592
597
  ### @option args :fut[Boolean] fill user template, defaults to false
593
598
  ###
594
- ### @option args :unmount[Boolean] unmount the distribution point when finished?(if we mounted it),
595
- ### defaults to false
599
+ ### @option args :unmount[Boolean] unmount the distribution point when
600
+ ### finished?(if we mounted it), defaults to false
601
+ ###
602
+ ### @option args :no_http[Boolean] don't use http downloads even if they
603
+ ### are enabled for the dist. point.
596
604
  ###
597
- ### @option args :no_http[Boolean] don't use http downloads even if they are enabled for the dist. point.
605
+ ### @option args :alt_download_url [String] Use this url for an http
606
+ ### download, regardless of distribution point settings. This can be used
607
+ ### to access Cloud Distribution Points if the fileshare isn't available.
608
+ ### The URL should already be ur
609
+ ### The package filename will be removed or appended as needed.
598
610
  ###
599
- ### @return [Process::Status] the final status of the jamf binary command
611
+ ### @return [Boolean] did the jamf install succeed?
600
612
  ###
601
- ### @todo deal with cert-based https authentication
613
+ ### @todo deal with cert-based https authentication in dist points
602
614
  ###
603
615
  def install (args = {})
604
616
 
@@ -608,46 +620,73 @@ module JSS
608
620
 
609
621
  ro_pw = args[:ro_pw]
610
622
 
611
- mdp = JSS::DistributionPoint.my_distribution_point
612
-
613
- ### how do we access our dist. point? with http?
614
- if mdp.http_downloads_enabled and (not args[:no_http])
615
- using_http = true
616
- src_path = mdp.http_url
617
- if mdp.username_password_required
618
- raise JSS::MissingDataError, "No password provided for http download" unless ro_pw
619
- raise JSS::InvaldDatatError, "Incorrect password for http access to distribution point." unless mdp.check_pw(:http, ro_pw)
620
- # insert the name and pw into the uri
621
- reserved_chars = Regexp.new("[^#{URI::REGEXP::PATTERN::UNRESERVED}]") # we'll escape all the chars that aren't unreserved
622
- src_path = src_path.sub(%r{(https?://)(\S)}, "#{$1}#{URI.escape mdp.http_username,reserved_chars}:#{URI.escape ro_pw, reserved_chars}@#{$2}")
623
+ # as of Casper 9.72, with http downloads, the jamf binary requires
624
+ # the filename must be at the end of the -path url, but before 9.72
625
+ # it can't be.
626
+ # e.g.
627
+ # in <9.72: jamf install -package foo.pkg -path http://mycasper.myorg.edu/CasperShare/Packages
628
+ # but
629
+ # in >=9.72: jamf install -package foo.pkg -path http://mycasper.myorg.edu/CasperShare/Packages/foo.pkg
630
+ #
631
+ append_at_vers = JSS.parse_jss_version("9.72")[:version]
632
+ our_vers = JSS.parse_jss_version(JSS::API.server.raw_version)[:version]
633
+ no_filename_in_url = (our_vers < append_at_vers)
634
+
635
+ # use a provided alternative url for an http download
636
+ if args[:alt_download_url]
637
+
638
+ # we'll re-add the filename below if needed.
639
+ src_path = args[:alt_download_url].chomp "/#{@filename}"
640
+
641
+ # use our appropriate dist. point for download
642
+ else
643
+ mdp = JSS::DistributionPoint.my_distribution_point
644
+
645
+ ### how do we access our dist. point? with http?
646
+ if mdp.http_downloads_enabled and (not args[:no_http])
647
+ using_http = true
648
+ src_path = mdp.http_url
649
+ if mdp.username_password_required
650
+ raise JSS::MissingDataError, "No password provided for http download" unless ro_pw
651
+ raise JSS::InvaldDatatError, "Incorrect password for http access to distribution point." unless mdp.check_pw(:http, ro_pw)
652
+ # insert the name and pw into the uri
653
+ reserved_chars = Regexp.new("[^#{URI::REGEXP::PATTERN::UNRESERVED}]") # we'll escape all the chars that aren't unreserved
654
+ src_path = src_path.sub(%r{(https?://)(\S)}, "#{$1}#{URI.escape mdp.http_username,reserved_chars}:#{URI.escape ro_pw, reserved_chars}@#{$2}")
655
+ end
656
+
657
+ # or with filesharing?
658
+ else
659
+ using_http = false
660
+ src_path = mdp.mount(ro_pw)
623
661
  end
624
662
 
625
- # or with filesharing?
626
- else
627
- using_http = false
628
- src_path = mdp.mount(ro_pw)
629
- end
663
+ # look at the pkgs folder
664
+ src_path += "#{DIST_POINT_PKGS_FOLDER}"
665
+ end # if args[:alt_download_url]
666
+
667
+ src_path += "/#{@filename}" unless no_filename_in_url
630
668
 
631
- # look at the pkgs folder
632
- src_path += "/#{DIST_POINT_PKGS_FOLDER}"
633
669
 
634
670
  ### are we doing "fill existing users" or "fill user template"?
635
671
  do_feu = args[:feu] ? "-feu" : ""
636
672
  do_fut = args[:fut] ? "-fut" : ""
637
673
 
638
674
  ### the install args for jamf
639
- command_args = "-package '#{@filename}' -path '#{src_path}' -target '#{args[:target]}' #{do_feu} #{do_fut} -showProgress -verbose ; echo jamfexit $?"
675
+ command_args = "-package '#{@filename}' -path '#{src_path}' -target '#{args[:target]}' #{do_feu} #{do_fut} -showProgress -verbose"
640
676
 
641
- ### run it via a client
677
+ ### run it via a client cmd
642
678
  install_out = JSS::Client.run_jamf :install, command_args, args[:verbose]
643
679
 
644
- install_exit = $?
680
+ install_out =~ %r{<exitCode>(\d+)</exitCode>}
681
+ install_exit = $1 ? $1.to_i : nil
682
+ install_exit ||= $?.exitstatus
683
+
645
684
 
646
685
  if (args.include? :unmount)
647
686
  mdp.unmount unless using_http
648
687
  end
649
688
 
650
- return install_exit
689
+ return install_exit == 0 ? true : false
651
690
  end
652
691
 
653
692
  ###
@@ -668,7 +707,7 @@ module JSS
668
707
  ### @return [Process::Status] the result of the 'jamf uninstall' command
669
708
  ###
670
709
  def uninstall (args = {})
671
-
710
+
672
711
  raise JSS::UnsupportedError, \
673
712
  "This package cannot be uninstalled. Please use CasperAdmin to index it and allow uninstalls" unless removable?
674
713
  raise JSS::UnsupportedError, "You must have root privileges to uninstall packages" unless JSS.superuser?
@@ -689,6 +728,18 @@ module JSS
689
728
 
690
729
 
691
730
 
731
+ ### What type of package is this?
732
+ ###
733
+ ### @return [Symbol] :pkg or :dmg or:unknown
734
+ ###
735
+ def type
736
+ case @filename
737
+ when /\.m?pkg(\.zip)?$/ then :pkg
738
+ when /\.dmg$/ then :dmg
739
+ else :unknown
740
+ end
741
+ end
742
+
692
743
 
693
744
  ################################
694
745
  ### Private Instance Methods
@@ -706,7 +757,7 @@ module JSS
706
757
  pkg = doc.add_element "package"
707
758
  pkg.add_element('allow_uninstalled').text = @allow_uninstalled
708
759
  pkg.add_element('boot_volume_required').text = @boot_volume_required
709
- pkg.add_element('category').text = @category
760
+ pkg.add_element('category').text = @category.to_s.casecmp("No category assigned") == 0 ? "" : @category
710
761
  pkg.add_element('filename').text = @filename
711
762
  pkg.add_element('fill_existing_users').text = @fill_existing_users
712
763
  pkg.add_element('fill_user_template').text = @fill_user_template
@@ -717,7 +768,7 @@ module JSS
717
768
  pkg.add_element('os_requirements').text = JSS.to_s_and_a(@os_requirements)[:stringform]
718
769
  pkg.add_element('priority').text = @priority
719
770
  pkg.add_element('reboot_required').text = @reboot_required
720
- pkg.add_element('required_processor').text = @required_processor
771
+ pkg.add_element('required_processor').text = @required_processor.to_s.empty? ? "None" : @required_processor
721
772
  pkg.add_element('send_notification').text = @send_notification
722
773
  pkg.add_element('switch_with_package').text = @switch_with_package
723
774
  return doc.to_s
@@ -741,7 +792,7 @@ module JSS
741
792
  alias boot boot_volume_required
742
793
  alias boot? boot_volume_required
743
794
  alias notify send_notification
744
-
795
+
745
796
  alias removable= allow_uninstalled=
746
797
  alias boot= boot_volume_required=
747
798
  alias feu= fill_existing_users=
@@ -754,6 +805,8 @@ module JSS
754
805
 
755
806
 
756
807
 
808
+
809
+
757
810
  end # class Package
758
811
 
759
812
  end # module jss