knife-pkg 0.0.3 → 0.1.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.
data/.gitignore CHANGED
@@ -16,5 +16,6 @@ test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
18
  vendor
19
+ .vagrant
19
20
 
20
- /tags
21
+ /tags
data/README.md CHANGED
@@ -11,45 +11,71 @@ This is a plugin for [Chef's](http://www.opscode.com/chef) [knife](http://docs.o
11
11
 
12
12
  List all updates:
13
13
 
14
+ - without `chef`
15
+
16
+ ```sh
17
+ $ knife pkg show updates "127.0.0.1" -z -x vagrant -P 'vagrant' -m -p 2222
18
+ ===> 127.0.0.1
19
+ base-files (new: 7.1wheezy2 | installed: 7.1wheezy1)
20
+ curl (new: 7.26.0-1+wheezy4 | installed: 7.26.0-1+wheezy3)
21
+ dmsetup (new: 2:1.02.74-8 | installed: 2:1.02.74-7)
22
+ dpkg (new: 1.16.12 | installed: 1.16.10)
23
+ ...
24
+ ```
25
+
26
+ - with `chef` search
27
+
14
28
  ```sh
15
29
  $ knife pkg show updates "*:*"
16
30
  ===> kpp1.example.com
17
- libxml2 (2.7.8.dfsg-2+squeeze7)
18
- postgresql-client-9.2 (9.2.4-2.pgdg60+1)
19
- gpgv (1.4.10-4+squeeze2)
20
- gnupg (1.4.10-4+squeeze2)
31
+ accountsservice (new: 0.6.15-2ubuntu9.6.1 | installed: 0.6.15-2ubuntu9.6)
32
+ apparmor (new: 2.7.102-0ubuntu3.9 | installed: 2.7.102-0ubuntu3.7)
33
+ apt (new: 0.8.16~exp12ubuntu10.15 | installed: 0.8.16~exp12ubuntu10.10)
34
+ apt-transport-https (new: 0.8.16~exp12ubuntu10.15 | installed: 0.8.16~exp12ubuntu10.10)
35
+ apt-utils (new: 0.8.16~exp12ubuntu10.15 | installed: 0.8.16~exp12ubuntu10.10)
36
+ apt-xapian-index (new: 0.44ubuntu5.1 | installed: 0.44ubuntu5)
37
+ ...
21
38
  ===> kpp2.example.com
22
- libxml2 (2.7.8.dfsg-2+squeeze7)
23
- postgresql-client-9.2 (9.2.4-2.pgdg60+1)
24
- gpgv (1.4.10-4+squeeze2)
25
- gnupg (1.4.10-4+squeeze2)
26
- ...
39
+ abrt-libs.x86_64 (new: 2.0.8-16.el6.centos.1 | installed: 2.0.8-15.el6.centos)
40
+ abrt-tui.x86_64 (new: 2.0.8-16.el6.centos.1 | installed: 2.0.8-15.el6.centos)
41
+ bash.x86_64 (new: 4.1.2-15.el6_4 | installed: 4.1.2-14.el6)
42
+ bind-libs.x86_64 (new: 32:9.8.2-0.17.rc1.el6_4.6 | installed: 32:9.8.2-0.17.rc1.el6)
43
+ bind-utils.x86_64 (new: 32:9.8.2-0.17.rc1.el6_4.6 | installed: 32:9.8.2-0.17.rc1.el6)
44
+ busybox.x86_64 (new: 1:1.15.1-16.el6_4 | installed: 1:1.15.1-15.el6)
45
+ ...
27
46
  ```
28
47
 
29
- Install updates with user interaction:
48
+ - install updates with user interaction:
30
49
 
31
50
  ```sh
32
51
  $ knife pkg install updates "chef_environment:beta"
33
52
  ===> beta.example.com
34
- The following updates are available:
35
- libxml2 (2.7.8.dfsg-2+squeeze7)
36
- libxml2-dev (2.7.8.dfsg-2+squeeze7)
37
- Should I update all packages? [y|n]: n
38
- Should I update libxml2 (2.7.8.dfsg-2+squeeze7)? [y|n]: y
39
- libxml2 (2.7.8.dfsg-2+squeeze7) updated!
40
- Should I update libxml2-dev (2.7.8.dfsg-2+squeeze7)? [y|n]: y
41
- libxml2-dev (2.7.8.dfsg-2+squeeze7) updated!
53
+ The following updates are available:
54
+ NetworkManager.x86_64 (new: 1:0.9.8.2-9.git20130709.fc19 | installed: 1:0.9.8.2-2.fc19)
55
+ NetworkManager-glib.x86_64 (new: 1:0.9.8.2-9.git20130709.fc19 | installed: 1:0.9.8.2-2.fc19)
56
+ audit.x86_64 (new: 2.3.2-1.fc19 | installed: 2.3.1-2.fc19)
57
+ audit-libs.x86_64 (new: 2.3.2-1.fc19 | installed: 2.3.1-2.fc19)
58
+ ...
59
+ Do you want to update all packages? [y|n]: n
60
+ Do you want to update audit.x86_64 (2.3.2-1.fc19)? [y|n]: y
61
+ Do you want to update NetworkManager.x86_64 (1:0.9.8.2-9.git20130709.fc19)? [y|n]: y
62
+ Do you want to update ca-certificates.noarch (2013.1.94-1.fc19)? [y|n]: y
63
+ Do you want to update cronie.x86_64 (1.4.10-7.fc19)? [y|n]: n
64
+ ...
42
65
  ===> beta.bar.de
43
- The following updates are available:
44
- libxml2 (2.7.8.dfsg-2+squeeze7)
45
- libxml2-dev (2.7.8.dfsg-2+squeeze7)
46
- Should I update all packages? [y|n]: y
47
- Updating...
48
- all packages updated!
49
- ...
66
+ The following updates are available:
67
+ ...
68
+ tzdata.noarch (new: 2013g-1.fc19 | installed: 2013c-1.fc19)
69
+ util-linux.x86_64 (new: 2.23.2-4.fc19 | installed: 2.23.1-3.fc19)
70
+ vim-minimal.x86_64 (new: 2:7.4.027-2.fc19 | installed: 2:7.3.944-1.fc19)
71
+ wget.x86_64 (new: 1.14-8.fc19 | installed: 1.14-5.fc19)
72
+ yum.noarch (new: 3.4.3-111.fc19 | installed: 3.4.3-99.fc19)
73
+ Do you want to update all packages? [y|n]: y
74
+ updating...
75
+ all packages updated!
50
76
  ```
51
77
 
52
- Install defined updates without confirmation, ask for all others:
78
+ - install defined updates without confirmation, ask for all others:
53
79
 
54
80
  ```sh
55
81
  $ knife pkg install updates "roles:webserver" -U "libxml2,gpgv,gnupg"
@@ -72,8 +98,7 @@ $ knife pkg install updates "roles:webserver" -U "libxml2,gpgv,gnupg"
72
98
  Updating gnupg (1.4.10-4+squeeze2)
73
99
  ===> s6.example.com
74
100
  Updating libxml2 (2.7.8.dfsg-2+squeeze7)
75
- ===> staging.fuchstreff.de
76
- ===> postgres-staging.sauspiel.de
101
+ ===> s6.example.com
77
102
  ===> s7.example.com
78
103
  Updating libxml2 (2.7.8.dfsg-2+squeeze7)
79
104
  ===> s8.example.com
@@ -81,11 +106,20 @@ $ knife pkg install updates "roles:webserver" -U "libxml2,gpgv,gnupg"
81
106
  ...
82
107
  ```
83
108
 
109
+ ## Supported Packet Managers
110
+
111
+ * apt
112
+ * yum
113
+ * *look at [example](https://github.com/hamann/knife-pkg/blob/master/lib/knife-pkg/controllers/yum.rb) and send PRs*
114
+
115
+ Which packet manager will be used depends on what `ohai` (or `chef`) reports as [`platform_family`](https://github.com/opscode/ohai/blob/master/lib/ohai/plugins/linux/platform.rb#L103) for a node. So it should work if your node is of type 'debian' (=> apt), 'fedora' or 'rhel' (=> yum)
116
+
117
+
84
118
  ## Requirements
85
119
 
86
120
  * SSH access
87
121
  * Chef(-Server) or anything else which supports `search(:node, "*:*")` (*not required when you use `-m`*)
88
- * when `-m` option is given, `ohai` has to be installed on the node
122
+ * when `-m` option is given, `ohai` has to be installed on the node ( sudo gem install ohai --no-ri --no-rdoc )
89
123
 
90
124
 
91
125
  ## Installation
@@ -103,12 +137,6 @@ Or install it yourself as:
103
137
  $ gem install knife-pkg
104
138
 
105
139
 
106
- ## Supported Platforms
107
-
108
- * Debian/Ubuntu
109
- * *look at [example](https://github.com/hamann/knife-pkg/blob/master/lib/knife-pkg/controllers/debian.rb) and send PRs*
110
-
111
-
112
140
  ## Overview
113
141
 
114
142
  The plugin inherits from `Knife::Ssh`, so almost all options and configuration settings are supported.
data/Vagrantfile CHANGED
@@ -1,6 +1,8 @@
1
1
  boxes = {
2
2
  :debian => { :image => "https://opscode-vm-bento.s3.amazonaws.com/vagrant/opscode_debian-7.1.0_provisionerless.box" },
3
- :ubuntu => { :image => "https://opscode-vm-bento.s3.amazonaws.com/vagrant/opscode_ubuntu-12.04_provisionerless.box" }
3
+ :ubuntu => { :image => "https://opscode-vm-bento.s3.amazonaws.com/vagrant/opscode_ubuntu-12.04_provisionerless.box" },
4
+ :centos => { :image => "https://opscode-vm-bento.s3.amazonaws.com/vagrant/opscode_centos-6.4_provisionerless.box" },
5
+ :fedora => { :image => "https://opscode-vm-bento.s3.amazonaws.com/vagrant/opscode-fedora-19_provisionerless.box" }
4
6
  }
5
7
 
6
8
  Vagrant::configure("2") do |config|
@@ -70,8 +70,8 @@ class Chef
70
70
  def node_by_hostname(hostname)
71
71
  node = nil
72
72
  if config[:manual]
73
- obj = Struct.new(:fqdn)
74
- node = obj.new(hostname)
73
+ node = Hash.new
74
+ node[:fqdn] = hostname
75
75
  else
76
76
  @action_nodes.each do |n|
77
77
  if hostname_by_attribute(n) == hostname
@@ -18,47 +18,62 @@ require 'knife-pkg'
18
18
 
19
19
  module Knife
20
20
  module Pkg
21
- class DebianPackageController < PackageController
21
+ class AptPackageController < PackageController
22
22
 
23
23
  def initialize(node, session, opts = {})
24
24
  super(node, session, opts)
25
25
  end
26
26
 
27
+ def dry_run_supported?
28
+ true
29
+ end
30
+
27
31
  def update_pkg_cache
28
- ShellCommand.exec("#{sudo}apt-get update", @session)
32
+ exec("#{sudo}apt-get update")
29
33
  end
30
34
 
31
35
  def last_pkg_cache_update
32
36
  raise_update_notifier_missing! unless update_notifier_installed?
33
37
 
34
- result = ShellCommand.exec("stat -c %y /var/lib/apt/periodic/update-success-stamp", @session)
35
- Time.parse(result.stdout.chomp)
38
+ result = nil
39
+ begin
40
+ result = exec("stat -c %y /var/lib/apt/periodic/update-success-stamp")
41
+ Time.parse(result.stdout.chomp)
42
+ rescue RuntimeError => e
43
+ e.backtrace.each { |l| Chef::Log.debug(l) }
44
+ Chef::Log.warn(e.message)
45
+ Time.now - (max_pkg_cache_age + 100)
46
+ end
36
47
  end
37
48
 
38
49
  def installed_version(package)
39
- ShellCommand.exec("dpkg -p #{package.name} | grep -i Version: | awk '{print $2}'", @session).stdout.chomp
50
+ exec("dpkg -p #{package.name} | grep -i Version: | awk '{print $2}' | head -1").stdout.chomp
51
+ end
52
+
53
+ def update_version(package)
54
+ exec("#{sudo} apt-cache policy #{package.name} | grep Candidate | awk '{print $2}'").stdout.chomp
40
55
  end
41
56
 
42
57
  def available_updates
43
58
  packages = Array.new
44
59
  raise_update_notifier_missing! unless update_notifier_installed?
45
- result = ShellCommand.exec("#{sudo}/usr/lib/update-notifier/apt_check.py -p", @session)
60
+ result = exec("#{sudo}/usr/lib/update-notifier/apt_check.py -p")
46
61
  result.stderr.split("\n").each do |item|
47
62
  package = Package.new(item)
48
- package.version = installed_version(package)
63
+ package.version = update_version(package)
49
64
  packages << package
50
65
  end
51
- packages
66
+ packages.sort { |n,m| n.name <=> m.name }
52
67
  end
53
68
 
54
69
  def update_package!(package)
55
70
  cmd_string = "#{sudo} DEBIAN_FRONTEND=noninteractive apt-get install #{package.name} -y -o Dpkg::Options::='--force-confold'"
56
71
  cmd_string += " -s" if @options[:dry_run]
57
- ShellCommand.exec(cmd_string, @session)
72
+ exec(cmd_string)
58
73
  end
59
74
 
60
75
  def update_notifier_installed?
61
- ShellCommand.exec("dpkg-query -W update-notifier-common 2>/dev/null || echo 'false'", @session).stdout.chomp != 'false'
76
+ exec("dpkg-query -W update-notifier-common 2>/dev/null || echo 'false'").stdout.chomp != 'false'
62
77
  end
63
78
 
64
79
  def raise_update_notifier_missing!
@@ -21,6 +21,8 @@ module Knife
21
21
  module Pkg
22
22
  class PackageController
23
23
 
24
+ ONE_DAY_IN_SECS = 86500
25
+
24
26
  attr_accessor :node
25
27
  attr_accessor :session
26
28
  attr_accessor :options
@@ -40,10 +42,23 @@ module Knife
40
42
  @options[:sudo] ? 'sudo ' : ''
41
43
  end
42
44
 
45
+ def exec(cmd)
46
+ ShellCommand.exec(cmd, @session)
47
+ end
48
+
49
+ def max_pkg_cache_age
50
+ options[:max_pkg_cache_age] || ONE_DAY_IN_SECS
51
+ end
52
+
43
53
  ## ++ methods to implement
44
54
 
45
55
  # update the package cache
46
56
  # e.g apt-get update
57
+
58
+ def dry_run_supported?
59
+ false
60
+ end
61
+
47
62
  def update_pkg_cache
48
63
  raise NotImplementedError
49
64
  end
@@ -58,6 +73,11 @@ module Knife
58
73
  raise NotImplementedError
59
74
  end
60
75
 
76
+ # returns the version string of the available update for a package
77
+ def update_version(package)
78
+ raise NotImplementedError
79
+ end
80
+
61
81
  # returns an `Array` of all available updates
62
82
  def available_updates
63
83
  raise NotImplementedError
@@ -72,8 +92,18 @@ module Knife
72
92
 
73
93
  ## ++ methods to implement
74
94
 
95
+ def update_info(packages)
96
+ result = []
97
+ packages.each do |pkg|
98
+ installed_version = installed_version(pkg)
99
+ result << "#{pkg.name} (new: #{pkg.version} | installed: #{installed_version})"
100
+ end
101
+ result
102
+ end
75
103
 
76
104
  def update_package_verbose!(package)
105
+ raise NotImplementedError, "\"dry run\" isn't supported for this platform! (maybe a bug)" if @options[:dry_run] && !dry_run_supported?
106
+
77
107
  result = update_package!(package)
78
108
  if @options[:dry_run] || @options[:verbose]
79
109
  ui.info(result.stdout)
@@ -82,7 +112,7 @@ module Knife
82
112
  end
83
113
 
84
114
  def try_update_pkg_cache
85
- if Time.now - last_pkg_cache_update > 86400 # 24 hours
115
+ if Time.now - last_pkg_cache_update > max_pkg_cache_age
86
116
  @ui.info("Updating package cache...")
87
117
  update_pkg_cache
88
118
  end
@@ -92,9 +122,7 @@ module Knife
92
122
  return if packages.count == 0
93
123
 
94
124
  ui.info("\tThe following updates are available:") if packages.count > 0
95
- packages.each do |package|
96
- ui.info(ui.color("\t" + package.to_s, :yellow))
97
- end
125
+ PackageController::list_available_updates(update_info(packages))
98
126
 
99
127
  if UserDecision.yes?("\tDo you want to update all packages? [y|n]: ")
100
128
  ui.info("\tupdating...")
@@ -118,6 +146,14 @@ module Knife
118
146
  end
119
147
  end
120
148
 
149
+ # Connects to the node, updates packages (defined with param `packages`) without confirmation, all other available updates with confirmation
150
+ # @param [Hash] node the node
151
+ # @option node [String] :platform_family platform of the node, e.g. `debian`. if not set, `ohai` will be executed
152
+ # @param [Session] session the ssh session to be used to connect to the node
153
+ # @param [Array<String>] packages name of the packages which should be updated without confirmation
154
+ # @param [Hash] opts the options
155
+ # @option opts [Boolean] :dry_run wether the update should only be simulated (if supported by the package manager)
156
+ # @option opts [Boolean] :verbose wether the update process should be more verbose
121
157
  def self.update!(node, session, packages, opts)
122
158
  ctrl = self.init_controller(node, session, opts)
123
159
 
@@ -127,6 +163,9 @@ module Knife
127
163
  ctrl.try_update_pkg_cache
128
164
  available_updates = ctrl.available_updates
129
165
 
166
+ # install packages in auto_updates without confirmation,
167
+ # but only if they are available as update
168
+ # don't install packages which aren't installed
130
169
  available_updates.each do |avail|
131
170
  if auto_updates.select { |p| p.name == avail.name }.count == 0
132
171
  updates_for_dialog << avail
@@ -143,38 +182,23 @@ module Knife
143
182
  ctrl = self.init_controller(node, session, opts)
144
183
  ctrl.try_update_pkg_cache
145
184
  updates = ctrl.available_updates
146
- list_available_updates(updates)
185
+ list_available_updates(ctrl.update_info(updates))
147
186
  end
148
187
 
149
188
  def self.init_controller(node, session, opts)
150
- begin
151
- ctrl_name = ''
152
- if node.has_key?(:platform)
153
- ctrl_name = self.controller_name(node.platform)
154
- else
155
- platform = self.platform_by_local_ohai(session, opts)
156
- ctrl_name = self.controller_name(platform)
157
- end
158
- require File.join(File.dirname(__FILE__), ctrl_name)
159
- rescue LoadError
160
- raise NotImplementedError, "I'm sorry, but #{node.platform} is not supported!"
161
- end
189
+ platform_family = node[:platform_family] || self.platform_family_by_local_ohai(session, opts)
190
+ ctrl_name = PlatformFamily.map_to_pkg_ctrl(platform_family)
191
+ raise NotImplementedError, "I'm sorry, but #{node[:platform_family]} is not supported!" if ctrl_name == 'unknown'
192
+
193
+ Chef::Log.debug("Platform Family #{platform_family} detected, using #{ctrl_name}")
194
+ require File.join(File.dirname(__FILE__), ctrl_name)
162
195
  ctrl = Object.const_get('Knife').const_get('Pkg').const_get("#{ctrl_name.capitalize}PackageController").new(node, session, opts)
163
196
  ctrl.ui = self.ui
164
197
  ctrl
165
198
  end
166
199
 
167
- def self.platform_by_local_ohai(session, opts)
168
- ShellCommand.exec("ohai platform| grep \\\"", session).stdout.strip.gsub(/\"/,'')
169
- end
170
-
171
- def self.controller_name(platform)
172
- case platform
173
- when 'debian', 'ubuntu'
174
- 'debian'
175
- else
176
- platform
177
- end
200
+ def self.platform_family_by_local_ohai(session, opts)
201
+ ShellCommand.exec("ohai platform_family| grep \\\"", session).stdout.strip.gsub(/\"/,'')
178
202
  end
179
203
  end
180
204
  end
@@ -0,0 +1,65 @@
1
+ #
2
+ # Copyright 2013, Holger Amann <holger@fehu.org>
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+
17
+ require 'knife-pkg'
18
+
19
+ module Knife
20
+ module Pkg
21
+ class YumPackageController < PackageController
22
+
23
+ def initialize(node, session, opts = {})
24
+ super(node, session, opts)
25
+ end
26
+
27
+ def dry_run_supported?
28
+ false
29
+ end
30
+
31
+ def update_pkg_cache
32
+ # not necessary
33
+ end
34
+
35
+ def last_pkg_cache_update
36
+ return Time.now
37
+ end
38
+
39
+ def installed_version(package)
40
+ exec("#{sudo}yum list installed | egrep \"^#{package.name}\" | awk '{print $2}'").stdout.chomp
41
+ end
42
+
43
+ def update_version(package)
44
+ exec("#{sudo}yum check-update -q | egrep \"^#{package.name}\" | awk '{print $2}'").stdout.chomp
45
+ end
46
+
47
+ def available_updates
48
+ packages = Array.new
49
+ result = exec("#{sudo}yum check-update -q| awk '{ print $1, $2 }'")
50
+ result.stdout.split("\n").each do |item|
51
+ next unless item.match(/^\s+$/).nil?
52
+ name, version = item.split(" ")
53
+ package = Package.new(name, version)
54
+ packages << package
55
+ end
56
+ packages
57
+ end
58
+
59
+ def update_package!(package)
60
+ cmd_string = "#{sudo}yum -d0 -e0 -y install #{package.name}"
61
+ exec(cmd_string)
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,18 @@
1
+ module Knife
2
+ module Pkg
3
+ class PlatformFamily
4
+ class << self
5
+ def map_to_pkg_ctrl(name)
6
+ case name
7
+ when 'debian'
8
+ 'apt'
9
+ when 'rhel', 'fedora'
10
+ 'yum'
11
+ else
12
+ 'unknown'
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,5 +1,5 @@
1
1
  module Knife
2
2
  module Pkg
3
- VERSION = '0.0.3'
3
+ VERSION = '0.1.0'
4
4
  end
5
5
  end
data/lib/knife-pkg.rb CHANGED
@@ -19,6 +19,7 @@ require 'knife-pkg/package'
19
19
  require 'knife-pkg/shell_command'
20
20
  require 'knife-pkg/shell_command_result'
21
21
  require 'knife-pkg/user_decision'
22
+ require 'knife-pkg/platform_family'
22
23
  require 'knife-pkg/controllers/package_controller'
23
24
 
24
25
  module Knife
@@ -0,0 +1,59 @@
1
+ require 'knife-pkg'
2
+ require 'knife-pkg/controllers/apt'
3
+
4
+ include Knife::Pkg
5
+
6
+ describe 'AptPackageController' do
7
+ describe '#new' do
8
+ it 'should create an instance of AptPkgCtrl' do
9
+ p = AptPackageController.new('a', 'b', :h => 1)
10
+ expect(p).to be_an_instance_of(AptPackageController)
11
+ expect(p.node).to eq('a')
12
+ expect(p.session).to eq('b')
13
+ expect(p.options).to eq(:h => 1)
14
+ end
15
+ end
16
+
17
+ describe '#dry_run_supported?' do
18
+ it 'should return true' do
19
+ p = AptPackageController.new(nil, nil, {})
20
+ expect(p.dry_run_supported?).to eq true
21
+ end
22
+ end
23
+
24
+ describe "#last_pkg_cache_update" do
25
+ it 'should return a time object' do
26
+ t = Time.now
27
+ result = ShellCommandResult.new(nil,"2013-10-07 09:58:34.000000000 +0200\n",nil,nil)
28
+
29
+ p = AptPackageController.new(nil, nil)
30
+ p.stub(:exec).and_return(result)
31
+ expect(p.last_pkg_cache_update).to be_an_instance_of Time
32
+ expect(p.last_pkg_cache_update).to eq(Time.parse("2013-10-07 09:58:34.000000000 +0200"))
33
+ end
34
+ end
35
+
36
+ describe "#available_updates" do
37
+ it 'should raise an error if update-notifier is not installed' do
38
+ p = AptPackageController.new(nil, nil)
39
+ p.stub(:update_notifier_installed?).and_return(false)
40
+ expect{p.available_updates}.to raise_error(/update-notifier/)
41
+ end
42
+
43
+ it 'should return an array' do
44
+ result = ShellCommandResult.new(nil, nil, "b\na\nc", nil)
45
+ p = AptPackageController.new(nil, nil)
46
+ p.stub(:exec).and_return(result)
47
+ p.stub(:update_notifier_installed?).and_return(true)
48
+ p.stub(:installed_version).and_return("1.0.0")
49
+ p.stub(:update_version).and_return("2.0.0")
50
+
51
+ updates = p.available_updates
52
+ expect(updates).to be_an_instance_of Array
53
+ expect(updates.count).to eq(3)
54
+ expect(updates[0].name).to eq("a")
55
+ expect(updates[1].name).to eq("b")
56
+ expect(updates[2].name).to eq("c")
57
+ end
58
+ end
59
+ end
@@ -3,6 +3,12 @@ require 'knife-pkg'
3
3
  include Knife::Pkg
4
4
 
5
5
  describe 'PackageController' do
6
+ before :each do
7
+ @ui = Object.new
8
+ @ui.stub(:info)
9
+ @ui.stub(:error)
10
+ end
11
+
6
12
  describe '#new' do
7
13
  end
8
14
 
@@ -18,11 +24,158 @@ describe 'PackageController' do
18
24
  end
19
25
  end
20
26
 
27
+ describe '#exec' do
28
+ it 'should call ShellCommand and return a ShellCommandResult' do
29
+ p = PackageController.new(nil, 'a')
30
+ cmd = "ls -l"
31
+ r = Struct.new(:stdout, :stderr)
32
+ result = r.new('a', 'b')
33
+ ShellCommand.stub(:exec).with(cmd, p.session).and_return(r)
34
+ expect(ShellCommand).to receive(:exec).with(cmd, p.session)
35
+ expect(p.exec(cmd)).to eq(r)
36
+ end
37
+ end
38
+
21
39
  describe '.init_controller' do
22
- it 'should initialize the right package controller' do
23
- FakeNode = Struct.new(:platform)
24
- node = FakeNode.new("debian")
25
- PackageController.init_controller(node, nil, nil)
40
+ it 'should initialize the right package controller if node[:platform_family] is not set' do
41
+ node = Hash.new
42
+ node[:platform_family] = 'debian'
43
+ expect(PackageController).to_not receive(:platform_family_by_local_ohai)
44
+ ctrl = PackageController.init_controller(node, nil, nil)
45
+ expect(ctrl).to be_an_instance_of AptPackageController
46
+ end
47
+
48
+ it 'should call ohai if node[:platform_family] is not set' do
49
+ PackageController.stub(:platform_family_by_local_ohai).and_return('debian')
50
+ expect(PackageController).to receive(:platform_family_by_local_ohai)
51
+ ctrl = PackageController.init_controller({}, nil, nil)
52
+ expect(ctrl).to be_an_instance_of AptPackageController
53
+ end
54
+
55
+ it 'should raise an error if platform family could not be mapped' do
56
+ node = { :platform_family => 'suse' }
57
+ expect{PackageController.init_controller(node, nil, {})}.to raise_error(NotImplementedError)
58
+ end
59
+
60
+ end
61
+
62
+ describe '#update_info' do
63
+ it 'should return an array of strings with package update information' do
64
+ ctrl = PackageController.new(nil, nil)
65
+ pkg = Package.new("a", "1.0.1")
66
+ pkg2 = Package.new("b", "2.0.2")
67
+
68
+ ctrl.stub(:installed_version).with(pkg).and_return("1.0.0")
69
+ ctrl.stub(:installed_version).with(pkg2).and_return("2.0.0")
70
+
71
+
72
+ strings = ctrl.update_info([pkg, pkg2])
73
+ expect(strings.count).to eq(2)
74
+ expect(strings[0]).to match(/a.+1\.0\.1.+1\.0\.0/)
75
+ expect(strings[1]).to match(/b.+2\.0\.2.+2\.0\.0/)
76
+ end
77
+ end
78
+
79
+ describe '#update_package_verbose!' do
80
+ it 'should raise an error if dry run is not supported' do
81
+ ctrl = PackageController.new(nil, nil, :dry_run => true)
82
+ expect{ctrl.update_package_verbose!([])}.to raise_error(NotImplementedError)
83
+ end
84
+
85
+ it 'should not print stdout and stderr dry_run or verbose are not set' do
86
+ ctrl = PackageController.new(nil, {})
87
+ ctrl.ui = @ui
88
+ r = Struct.new(:stdout, :stderr)
89
+ result = r.new("a", "b")
90
+
91
+ ctrl.stub(:update_package!).and_return(result)
92
+ expect(ctrl.ui).to_not receive(:info)
93
+ expect(ctrl.ui).to_not receive(:error)
94
+ ctrl.update_package_verbose!([0])
95
+ end
96
+
97
+ it 'should print stdout and stderr if dry_run is set' do
98
+ ctrl = PackageController.new(nil, {})
99
+ ctrl.ui = @ui
100
+ r = Struct.new(:stdout, :stderr)
101
+ result = r.new("a", "b")
102
+
103
+ ctrl.options[:dry_run] = true
104
+ ctrl.stub(:dry_run_supported?).and_return(true)
105
+ ctrl.stub(:update_package!).and_return(result)
106
+ expect(ctrl.ui).to receive(:info).with("a")
107
+ expect(ctrl.ui).to receive(:error).with("b")
108
+ ctrl.update_package_verbose!([0])
109
+ end
110
+
111
+ it 'should print stdout and stderr if verbose is set' do
112
+ ctrl = PackageController.new(nil, {})
113
+ ctrl.ui = @ui
114
+
115
+ r = Struct.new(:stdout, :stderr)
116
+ result = r.new("a", "b")
117
+
118
+ ctrl.options[:dry_run] = true
119
+ ctrl.stub(:dry_run_supported?).and_return(true)
120
+ ctrl.stub(:update_package!).and_return(result)
121
+ expect(ctrl.ui).to receive(:info).with("a")
122
+ expect(ctrl.ui).to receive(:error).with("b")
123
+ ctrl.update_package_verbose!([0])
124
+ end
125
+ end
126
+
127
+ describe "#try_update_pkg_cache" do
128
+ it 'should call update_pkg_cache' do
129
+ ctrl = PackageController.new(nil, nil)
130
+ ctrl.ui = @ui
131
+ ctrl.stub(:last_pkg_cache_update).and_return(Time.now - PackageController::ONE_DAY_IN_SECS)
132
+ expect(ctrl).to receive(:update_pkg_cache)
133
+ ctrl.try_update_pkg_cache
134
+ end
135
+ end
136
+
137
+ describe '.list_available_updates' do
138
+ it 'should list available updates' do
139
+ p = Package.new('1'); p2 = Package.new('p2')
140
+ Chef::Knife::UI.any_instance.stub(:info)
141
+ PackageController.list_available_updates([p,p2])
142
+ end
143
+ end
144
+
145
+ describe '.platform_family_by_local_ohai' do
146
+ it 'should call ohai to determine the platform family' do
147
+ r = Struct.new(:stdout)
148
+ result = r.new(" \"mac_os_x\"")
149
+ ShellCommand.stub(:exec).and_return(result)
150
+ expect(ShellCommand).to receive(:exec)
151
+ expect(PackageController.platform_family_by_local_ohai(nil, nil)).to eq("mac_os_x")
152
+ end
153
+ end
154
+
155
+ describe '.update!' do
156
+ it 'should install available updates' do
157
+ node = { :platform_family => 'debian' }
158
+ packages = ["a","b","c"]
159
+ package_for_dialog = Package.new("d")
160
+ available_updates = [ Package.new("a"), Package.new("b"), package_for_dialog ]
161
+
162
+ ctrl = PackageController.new(node, nil, {})
163
+ ctrl.ui = @ui
164
+ Chef::Knife::UI.any_instance.stub(:info)
165
+
166
+ PackageController.stub(:init_controller).with(node, nil, {}).and_return(ctrl)
167
+ ctrl.stub(:try_update_pkg_cache)
168
+ ctrl.stub(:available_updates).and_return(available_updates)
169
+ ctrl.stub(:update_package_verbose!).with([Package.new("a"), Package.new("b")])
170
+ ctrl.stub(:dry_run_supported?).and_return(true)
171
+ ctrl.stub(:update_dialog).with([package_for_dialog])
172
+
173
+ expect(PackageController).to receive(:init_controller).with(node, nil, {})
174
+ expect(ctrl).to receive(:try_update_pkg_cache)
175
+ expect(ctrl).to receive(:available_updates)
176
+ expect(ctrl).to receive(:update_package_verbose!).exactly(2).times
177
+ expect(ctrl).to receive(:update_dialog).with([package_for_dialog])
178
+ PackageController.update!(node, nil, packages, {})
26
179
  end
27
180
  end
28
181
  end
@@ -0,0 +1,84 @@
1
+ require 'knife-pkg'
2
+ require 'knife-pkg/controllers/yum'
3
+
4
+ include Knife::Pkg
5
+
6
+ describe 'YumPackageController' do
7
+ describe '#new' do
8
+ it 'should create an instance of YumPkgCtrl' do
9
+ p = YumPackageController.new('a', 'b', :h => 1)
10
+ expect(p).to be_an_instance_of(YumPackageController)
11
+ expect(p.node).to eq('a')
12
+ expect(p.session).to eq('b')
13
+ expect(p.options).to eq(:h => 1)
14
+ end
15
+ end
16
+
17
+ describe "#dry_run_supported?" do
18
+ it 'should return false' do
19
+ p = YumPackageController.new(nil, nil, {})
20
+ expect(p.dry_run_supported?).to eq false
21
+ end
22
+ end
23
+
24
+ describe "#last_pkg_cache_update" do
25
+ it 'should return a time object' do
26
+ p = YumPackageController.new(nil, nil)
27
+ expect(p.last_pkg_cache_update).to be_an_instance_of Time
28
+ expect(p.last_pkg_cache_update.to_s).to eq(Time.now.to_s)
29
+ end
30
+ end
31
+
32
+ describe "#installed_version" do
33
+ it 'should return the installed version of a package as string' do
34
+ r = Struct.new(:stdout)
35
+ result = r.new("3.2.29-40.el6.centos\n")
36
+
37
+ p = YumPackageController.new(nil, nil)
38
+ p.stub(:exec).and_return(result)
39
+ expect(p).to receive(:sudo)
40
+ expect(p.installed_version(Package.new("a"))).to eq("3.2.29-40.el6.centos")
41
+ end
42
+ end
43
+
44
+ describe "#update_version" do
45
+ it 'should return the installed version of a package as string' do
46
+ r = Struct.new(:stdout)
47
+ result = r.new("3.2.29-40.el6.centos\n")
48
+
49
+ p = YumPackageController.new(nil, nil)
50
+ p.stub(:exec).and_return(result)
51
+ expect(p).to receive(:sudo)
52
+ expect(p.update_version(Package.new("a"))).to eq("3.2.29-40.el6.centos")
53
+ end
54
+ end
55
+
56
+ describe "#available_updates" do
57
+ it 'should return an array of packages' do
58
+ r = Struct.new(:stdout)
59
+ result = r.new(" \nabrt.x86_64 2.0.8-16.el6.centos.1\nabrt-addon-ccpp.x86_64 2.0.8-16.el6.centos.1\n")
60
+
61
+ p = YumPackageController.new(nil, nil)
62
+ p.stub(:exec).and_return(result)
63
+
64
+ expect(p).to receive(:sudo)
65
+
66
+ updates = p.available_updates
67
+ expect(updates.count).to eq(2)
68
+ expect(updates[0].name).to eq("abrt.x86_64")
69
+ expect(updates[0].version).to eq("2.0.8-16.el6.centos.1")
70
+ expect(updates[1].name).to eq("abrt-addon-ccpp.x86_64")
71
+ expect(updates[1].version).to eq("2.0.8-16.el6.centos.1")
72
+ end
73
+ end
74
+
75
+ describe "#update_package!" do
76
+ it 'should update a package and return a ShellCommandResult' do
77
+ p = YumPackageController.new(nil, nil)
78
+ r = ShellCommandResult.new(nil,nil, "1\n2\n3", nil)
79
+ p.stub(:exec).and_return(r)
80
+ expect(p.update_package!(Package.new("a"))).to eq(r)
81
+ end
82
+ end
83
+ end
84
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knife-pkg
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-10-15 00:00:00.000000000 Z
12
+ date: 2013-10-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: chef
@@ -94,15 +94,18 @@ files:
94
94
  - lib/chef/knife/pkg_install_updates.rb
95
95
  - lib/chef/knife/pkg_show_updates.rb
96
96
  - lib/knife-pkg.rb
97
- - lib/knife-pkg/controllers/debian.rb
97
+ - lib/knife-pkg/controllers/apt.rb
98
98
  - lib/knife-pkg/controllers/package_controller.rb
99
+ - lib/knife-pkg/controllers/yum.rb
99
100
  - lib/knife-pkg/package.rb
101
+ - lib/knife-pkg/platform_family.rb
100
102
  - lib/knife-pkg/shell_command.rb
101
103
  - lib/knife-pkg/shell_command_result.rb
102
104
  - lib/knife-pkg/user_decision.rb
103
105
  - lib/knife-pkg/version.rb
104
- - spec/controllers/debian_spec.rb
106
+ - spec/controllers/apt_spec.rb
105
107
  - spec/controllers/package_controller_spec.rb
108
+ - spec/controllers/yum_spec.rb
106
109
  - spec/package_spec.rb
107
110
  - spec/spec_helper.rb
108
111
  homepage: https://github.com/hamann/knife-pkg
@@ -120,7 +123,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
120
123
  version: '0'
121
124
  segments:
122
125
  - 0
123
- hash: 1027772782090820224
126
+ hash: 2359845024250157350
124
127
  required_rubygems_version: !ruby/object:Gem::Requirement
125
128
  none: false
126
129
  requirements:
@@ -129,7 +132,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
129
132
  version: '0'
130
133
  segments:
131
134
  - 0
132
- hash: 1027772782090820224
135
+ hash: 2359845024250157350
133
136
  requirements: []
134
137
  rubyforge_project:
135
138
  rubygems_version: 1.8.25
@@ -137,7 +140,8 @@ signing_key:
137
140
  specification_version: 3
138
141
  summary: A plugin for chef's knife to manage package updates
139
142
  test_files:
140
- - spec/controllers/debian_spec.rb
143
+ - spec/controllers/apt_spec.rb
141
144
  - spec/controllers/package_controller_spec.rb
145
+ - spec/controllers/yum_spec.rb
142
146
  - spec/package_spec.rb
143
147
  - spec/spec_helper.rb
@@ -1,45 +0,0 @@
1
- require 'knife-pkg'
2
- require 'knife-pkg/controllers/debian'
3
-
4
- include Knife::Pkg
5
-
6
- describe 'DebianPackageController' do
7
- describe '#new' do
8
- it 'should create an instance of DebianPkgCtrl' do
9
- p = DebianPackageController.new('a', 'b', :h => 1)
10
- expect(p).to be_an_instance_of(DebianPackageController)
11
- expect(p.node).to eq('a')
12
- expect(p.session).to eq('b')
13
- expect(p.options).to eq(:h => 1)
14
- end
15
- end
16
-
17
- describe "#last_pkg_cache_update" do
18
- it 'should return a time object' do
19
- t = Time.now
20
- result = ShellCommandResult.new(nil,"2013-10-07 09:58:34.000000000 +0200\n",nil,nil)
21
- ShellCommand.stub(:exec).and_return(result)
22
-
23
- p = DebianPackageController.new(nil, nil)
24
- expect(p.last_pkg_cache_update).to be_an_instance_of Time
25
- expect(p.last_pkg_cache_update).to eq(Time.parse("2013-10-07 09:58:34.000000000 +0200"))
26
- end
27
- end
28
-
29
- describe "#available_updates" do
30
- it 'should raise an error if update-notifier is not installed' do
31
- p = DebianPackageController.new(nil, nil)
32
- p.stub(:update_notifier_installed?).and_return(false)
33
- expect{p.available_updates}.to raise_error(/update-notifier/)
34
- end
35
-
36
- it 'should return an array' do
37
- result = ShellCommandResult.new(nil, nil, "1\n2\n3", nil)
38
- ShellCommand.stub(:exec).and_return(result)
39
- p = DebianPackageController.new(nil, nil)
40
- p.stub(:update_notifier_installed?).and_return(true)
41
- p.stub(:installed_version).and_return("1.0.0")
42
- expect(p.available_updates).to be_an_instance_of Array
43
- end
44
- end
45
- end