pandler 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +23 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +47 -0
- data/Rakefile +10 -0
- data/Vagrantfile +33 -0
- data/bin/pandle +8 -0
- data/etc/yum/pandler.py +52 -0
- data/lib/pandler.rb +8 -0
- data/lib/pandler/chroot.rb +229 -0
- data/lib/pandler/cli.rb +40 -0
- data/lib/pandler/version.rb +3 -0
- data/lib/pandler/yumfile.rb +26 -0
- data/lib/pandler/yumrepo.rb +240 -0
- data/pandler.gemspec +24 -0
- data/spec/pandler/chroot_spec.rb +93 -0
- data/spec/pandler/cli_spec.rb +20 -0
- data/spec/pandler/yumfile_spec.rb +20 -0
- data/spec/pandler/yumrepo_spec.rb +152 -0
- data/spec/pandler_spec.rb +8 -0
- data/spec/resources/yumrepo/pandler-test-0.0.1-1.x86_64.rpm +0 -0
- data/spec/resources/yumrepo/pandler-test-a-0.0.1-1.x86_64.rpm +0 -0
- data/spec/resources/yumrepo/pandler-test-a-0.0.2-1.x86_64.rpm +0 -0
- data/spec/resources/yumrepo/pandler-test-dep-a-0.0.1-1.x86_64.rpm +0 -0
- data/spec/resources/yumrepo/pandler-test-dep-b-0.0.1-1.x86_64.rpm +0 -0
- data/spec/resources/yumrepo/pandler-test-dep-required-0.0.1-1.x86_64.rpm +0 -0
- data/spec/resources/yumrepo/pandler-test-dep-required-required-0.0.1-1.x86_64.rpm +0 -0
- data/spec/resources/yumrepo/repodata/09267893997a9b34726567132f642093ebd2a4b5e65096a6562efc3a29106723-other.xml.gz +0 -0
- data/spec/resources/yumrepo/repodata/596e9069dad80db19e7ba4c36b3df1e52583231b95bfa61186408c77520a213a-primary.xml.gz +0 -0
- data/spec/resources/yumrepo/repodata/7dd30f881bb1b1cbd723a5fa9d996b96805e25015b56140c99a444bf248c4260-other.sqlite.bz2 +0 -0
- data/spec/resources/yumrepo/repodata/8e6f832a8605163914b5aaf46e42daeaad10f9785d202c6c99c9d903354b3194-filelists.xml.gz +0 -0
- data/spec/resources/yumrepo/repodata/a810cd5676bb578a196231dae1f37179241630f6745a3d33691279ff61bfe175-primary.sqlite.bz2 +0 -0
- data/spec/resources/yumrepo/repodata/ad696c5b02dadaef085b16712ce0464ae0d4c102b3ccf1ce0f14e371a119463a-filelists.sqlite.bz2 +0 -0
- data/spec/resources/yumrepo/repodata/repomd.xml +55 -0
- data/spec/spec_helper.rb +82 -0
- data/vagrant_file.sh +30 -0
- metadata +156 -0
data/.gitignore
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
.*.swp
|
19
|
+
bin/*
|
20
|
+
!bin/pandle
|
21
|
+
.vagrant
|
22
|
+
vendor/bundle
|
23
|
+
spec/resources/repo
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Ryosuke IWANAGA
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# Pandler
|
2
|
+
Manage your packages with chroot.
|
3
|
+
|
4
|
+
Pandler(= Package + Bundler) helps managing rpm/yum packages. Using `Yumfile` and `Yumfile.lock`, Pandler automatically creates a locked chroot environment.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
*Currently Pandler support only root user usage because of `mount`. You should install and run as root user.*
|
9
|
+
|
10
|
+
Add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
gem 'pandler'
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ bundle
|
17
|
+
|
18
|
+
Or install it yourself as:
|
19
|
+
|
20
|
+
$ gem install pandler
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
Write `Yumfile`.
|
25
|
+
|
26
|
+
repo "base", "http://vault.centos.org/6.2/os/x86_64/"
|
27
|
+
|
28
|
+
rpm "basesystem"
|
29
|
+
rpm ""
|
30
|
+
|
31
|
+
Run `pandle install`.
|
32
|
+
|
33
|
+
# pandle install
|
34
|
+
# pandle list
|
35
|
+
|
36
|
+
Then, you can execute any command in the chroot environment.
|
37
|
+
|
38
|
+
# pandle exec pwd
|
39
|
+
/
|
40
|
+
|
41
|
+
## Contributing
|
42
|
+
|
43
|
+
1. Fork it
|
44
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
45
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
46
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
47
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/Vagrantfile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
Vagrant.configure("2") do |vagrant|
|
2
|
+
define_list = [
|
3
|
+
{
|
4
|
+
:name => :centos,
|
5
|
+
:box => "Berkshelf-CentOS-6.3-x86_64-minimal",
|
6
|
+
:box_url => "http://dl.dropbox.com/u/31081437/Berkshelf-CentOS-6.3-x86_64-minimal.box",
|
7
|
+
:pkgm => :yum,
|
8
|
+
},
|
9
|
+
# {
|
10
|
+
# :name => :ubuntu,
|
11
|
+
# :box => "precise64",
|
12
|
+
# :box_url => "http://files.vagrantup.com/precise64.box",
|
13
|
+
# :pkgm => :apt,
|
14
|
+
# },
|
15
|
+
]
|
16
|
+
|
17
|
+
vagrant.vm.provider :virtualbox do |v|
|
18
|
+
v.customize ["modifyvm", :id, "--memory", 256]
|
19
|
+
v.customize ["modifyvm", :id, "--cpus", 4]
|
20
|
+
end
|
21
|
+
|
22
|
+
define_list.each_with_index do |define, i|
|
23
|
+
vagrant.vm.define define[:name] do |config|
|
24
|
+
config.vm.box = define[:box]
|
25
|
+
config.vm.box_url = define[:box_url]
|
26
|
+
|
27
|
+
config.vm.hostname = define[:name].to_s
|
28
|
+
config.vm.network :private_network, ip: "192.168.50.#{i + 10}"
|
29
|
+
|
30
|
+
config.vm.provision :shell, :path => "vagrant_file.sh"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/bin/pandle
ADDED
data/etc/yum/pandler.py
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
from yum.plugins import PluginYumExit, TYPE_INTERACTIVE
|
2
|
+
import sys
|
3
|
+
import pprint
|
4
|
+
|
5
|
+
requires_api_version = '2.1'
|
6
|
+
plugin_type = (TYPE_INTERACTIVE,)
|
7
|
+
|
8
|
+
def config_hook(conduit):
|
9
|
+
parser = conduit.getOptParser()
|
10
|
+
if hasattr(parser, 'plugin_option_group'):
|
11
|
+
parser = parser.plugin_option_group
|
12
|
+
|
13
|
+
def postresolve_hook(conduit):
|
14
|
+
persistdir = conduit._base._conf.persistdir
|
15
|
+
pkgs = [x[0] for x in conduit.getTsInfo().pkgdict.values()]
|
16
|
+
|
17
|
+
file = open(persistdir+"/pandler.log", "w")
|
18
|
+
for pkg in pkgs:
|
19
|
+
relatedto_list = [x[0] for x in set(pkg.relatedto)]
|
20
|
+
|
21
|
+
dic = {
|
22
|
+
"package" : __pkg_to_s(pkg),
|
23
|
+
"name" : pkg.name,
|
24
|
+
"version" : pkg.version,
|
25
|
+
"release" : pkg.release,
|
26
|
+
"arch" : pkg.arch,
|
27
|
+
}
|
28
|
+
if len(relatedto_list) == 0:
|
29
|
+
ltsv = u"\t".join(k + u":" + v for k, v in dic.iteritems())
|
30
|
+
# print(ltsv)
|
31
|
+
file.write(ltsv + "\n")
|
32
|
+
else:
|
33
|
+
for relatedto in relatedto_list:
|
34
|
+
dic["relatedto"] = __pkg_to_s(relatedto)
|
35
|
+
ltsv = u"\t".join(k + u":" + v for k, v in dic.iteritems())
|
36
|
+
# print(ltsv)
|
37
|
+
file.write(ltsv + "\n")
|
38
|
+
|
39
|
+
file.close()
|
40
|
+
|
41
|
+
def postdownload_hook(conduit):
|
42
|
+
opts, commands = conduit.getCmdLine()
|
43
|
+
# Don't die on errors, or we'll never see them.
|
44
|
+
if not conduit.getErrors():
|
45
|
+
sys.exit(0)
|
46
|
+
|
47
|
+
def __pkg_to_s(pkg):
|
48
|
+
name = pkg.name
|
49
|
+
version = pkg.version
|
50
|
+
release = pkg.release
|
51
|
+
arch = pkg.arch
|
52
|
+
return "%(name)s-%(version)s-%(release)s.%(arch)s" % locals()
|
data/lib/pandler.rb
ADDED
@@ -0,0 +1,229 @@
|
|
1
|
+
require "etc"
|
2
|
+
require "open3"
|
3
|
+
|
4
|
+
class Pandler::Chroot
|
5
|
+
attr_reader :base_dir, :root_dir, :yumrepo, :mounts
|
6
|
+
|
7
|
+
def initialize(args = {})
|
8
|
+
@base_dir = args[:base_dir] || File.expand_path("pandler")
|
9
|
+
@root_dir = args[:root_dir] || File.join(base_dir, "root")
|
10
|
+
@yumrepo = args[:yumrepo] || "file://" + File.join(base_dir, "yumrepo")
|
11
|
+
|
12
|
+
@mounts = [
|
13
|
+
{ :type => 'proc', :path => '/proc' },
|
14
|
+
{ :type => 'sysfs', :path => '/sys' },
|
15
|
+
{ :type => 'tmpfs', :path => '/dev/shm' },
|
16
|
+
{ :type => 'devpts', :path => '/dev/pts',
|
17
|
+
:options => "gid=#{Etc.getgrnam("tty").gid},mode=0620,ptmxmode=0666,newinstance" },
|
18
|
+
]
|
19
|
+
end
|
20
|
+
|
21
|
+
def real_path(path)
|
22
|
+
File.join(root_dir, path)
|
23
|
+
end
|
24
|
+
|
25
|
+
def init
|
26
|
+
setup_dirs
|
27
|
+
setup_files
|
28
|
+
setup_devs
|
29
|
+
mount_all
|
30
|
+
true
|
31
|
+
end
|
32
|
+
|
33
|
+
def install(*pkgs)
|
34
|
+
yum_install(*pkgs)
|
35
|
+
rpm_erase_exclude(*pkgs)
|
36
|
+
end
|
37
|
+
|
38
|
+
def installed_pkgs
|
39
|
+
rpm_qa
|
40
|
+
end
|
41
|
+
|
42
|
+
def execute(*cmd)
|
43
|
+
chroot_run_cmd(*cmd)
|
44
|
+
end
|
45
|
+
|
46
|
+
def clean
|
47
|
+
umount_all
|
48
|
+
FileUtils.remove_entry_secure root_dir
|
49
|
+
end
|
50
|
+
|
51
|
+
def list
|
52
|
+
rpm_qa
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def yum_install(*pkgs)
|
58
|
+
cmd = ["yum", "--installroot", root_dir, "install"] + pkgs
|
59
|
+
run_cmd(*cmd)
|
60
|
+
end
|
61
|
+
|
62
|
+
def rpm_erase_exclude(*pkgs)
|
63
|
+
remove_pkgs = gratuitous_pkgs(*pkgs)
|
64
|
+
if remove_pkgs.size > 0
|
65
|
+
cmd = ["rpm", "--root", root_dir, "--erase"] + remove_pkgs
|
66
|
+
run_cmd(*cmd)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def gratuitous_pkgs(*pkgs)
|
71
|
+
rpm_qa - pkgs
|
72
|
+
end
|
73
|
+
|
74
|
+
def rpm_qa
|
75
|
+
run_cmd_capture_stdout("rpm", "--root", root_dir, "-qa").sort
|
76
|
+
end
|
77
|
+
|
78
|
+
def run_cmd(*cmd)
|
79
|
+
ret = Kernel.system(*cmd)
|
80
|
+
raise "command failed(ret: #{ret}) '#{cmd.join(" ")}'" unless ret
|
81
|
+
end
|
82
|
+
|
83
|
+
def chroot_run_cmd(*cmd)
|
84
|
+
run_cmd("chroot", root_dir, *cmd)
|
85
|
+
end
|
86
|
+
|
87
|
+
def run_cmd_capture_stdout(*cmd)
|
88
|
+
Open3.popen3(*cmd) do |stdin, stdout, stderr|
|
89
|
+
stdin.close
|
90
|
+
stdout.readlines.map { |l| l.chomp }
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def write_file(path, content)
|
95
|
+
open(real_path(path), "w") { |f| f.write content }
|
96
|
+
end
|
97
|
+
|
98
|
+
def mount_all
|
99
|
+
@mounts.each do |entry|
|
100
|
+
mount(entry)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def mount(entry)
|
105
|
+
unless mounted?(entry)
|
106
|
+
cmd = ["mount", "-t", entry[:type]]
|
107
|
+
cmd.concat ["-o", entry[:options]] if entry.has_key?(:options)
|
108
|
+
cmd.concat ["pandler_mount", real_path(entry[:path])]
|
109
|
+
run_cmd(*cmd)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def mounted?(entry)
|
114
|
+
`mount`.split("\n").map { |line| line.split[2] }.include?(real_path(entry[:path]))
|
115
|
+
end
|
116
|
+
|
117
|
+
def umount_all
|
118
|
+
@mounts.each do |entry|
|
119
|
+
umount(entry)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def umount(entry)
|
124
|
+
if mounted?(entry)
|
125
|
+
cmd = ["umount", "-l", real_path(entry[:path])]
|
126
|
+
run_cmd(*cmd)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def setup_dirs
|
131
|
+
FileUtils.mkdir_p root_dir
|
132
|
+
dirs = [
|
133
|
+
'/var/lib/rpm',
|
134
|
+
'/var/lib/yum',
|
135
|
+
'/var/lib/dbus',
|
136
|
+
'/var/log',
|
137
|
+
'/var/lock/rpm',
|
138
|
+
'/var/cache/yum',
|
139
|
+
'/etc/rpm',
|
140
|
+
'/tmp',
|
141
|
+
'/tmp/ccache',
|
142
|
+
'/var/tmp',
|
143
|
+
'/etc/yum.repos.d',
|
144
|
+
'/etc/yum',
|
145
|
+
'/proc',
|
146
|
+
'/sys',
|
147
|
+
]
|
148
|
+
dirs.each do |dir|
|
149
|
+
FileUtils.mkdir_p real_path(dir)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def setup_files
|
154
|
+
files = [
|
155
|
+
'/etc/mtab',
|
156
|
+
'/etc/fstab',
|
157
|
+
'/var/log/yum.log',
|
158
|
+
]
|
159
|
+
files.each do |file|
|
160
|
+
FileUtils.touch real_path(file)
|
161
|
+
end
|
162
|
+
|
163
|
+
write_file("/etc/yum/yum.conf", yum_conf)
|
164
|
+
FileUtils.ln_s("yum/yum.conf", real_path("/etc/yum.conf"), { :force => true })
|
165
|
+
FileUtils.cp("/etc/resolv.conf", real_path("/etc/resolv.conf"))
|
166
|
+
FileUtils.cp("/etc/hosts", real_path("/etc/hosts"))
|
167
|
+
end
|
168
|
+
|
169
|
+
def setup_devs
|
170
|
+
FileUtils.mkdir_p real_path("/dev/pts")
|
171
|
+
FileUtils.mkdir_p real_path("/dev/shm")
|
172
|
+
|
173
|
+
python_code = <<-PYTHON
|
174
|
+
import sys, os, os.path, stat
|
175
|
+
devFiles = [
|
176
|
+
(stat.S_IFCHR | 0666, os.makedev(1, 3), "#{real_path("/dev/null")}"),
|
177
|
+
(stat.S_IFCHR | 0666, os.makedev(1, 7), "#{real_path("/dev/full")}"),
|
178
|
+
(stat.S_IFCHR | 0666, os.makedev(1, 5), "#{real_path("/dev/zero")}"),
|
179
|
+
(stat.S_IFCHR | 0666, os.makedev(1, 8), "#{real_path("/dev/random")}"),
|
180
|
+
(stat.S_IFCHR | 0444, os.makedev(1, 9), "#{real_path("/dev/urandom")}"),
|
181
|
+
(stat.S_IFCHR | 0666, os.makedev(5, 0), "#{real_path("/dev/tty")}"),
|
182
|
+
(stat.S_IFCHR | 0600, os.makedev(5, 1), "#{real_path("/dev/console")}"),
|
183
|
+
# (stat.S_IFCHR | 0666, os.makedev(5, 2), "#{real_path("/dev/ptmx")}"),
|
184
|
+
]
|
185
|
+
for i in devFiles:
|
186
|
+
if os.path.exists(i[2]):
|
187
|
+
continue
|
188
|
+
else:
|
189
|
+
os.mknod(i[2], i[0], i[1])
|
190
|
+
sys.exit(0)
|
191
|
+
PYTHON
|
192
|
+
run_cmd("python", "-c", python_code)
|
193
|
+
|
194
|
+
FileUtils.symlink("/proc/self/fd/0", real_path("/dev/stdin"), { :force => true })
|
195
|
+
FileUtils.symlink("/proc/self/fd/1", real_path("/dev/stdout"), { :force => true })
|
196
|
+
FileUtils.symlink("/proc/self/fd/2", real_path("/dev/stderr"), { :force => true })
|
197
|
+
|
198
|
+
FileUtils.chown(Etc.getpwnam("root").uid, Etc.getgrnam("tty").gid, real_path("/dev/tty"))
|
199
|
+
# FileUtils.chown(Etc.getpwnam("root").uid, Etc.getgrnam("tty").gid, real_path("/dev/ptmx"))
|
200
|
+
|
201
|
+
unless File.exists? real_path("/dev/fd")
|
202
|
+
FileUtils.symlink("/proc/self/fd", real_path("/dev/fd"), { :force => true })
|
203
|
+
end
|
204
|
+
FileUtils.symlink("pts/ptmx", real_path("/dev/ptmx"), { :force => true })
|
205
|
+
end
|
206
|
+
|
207
|
+
def yum_conf
|
208
|
+
content = <<-EOF
|
209
|
+
[main]
|
210
|
+
cachedir=/var/cache/yum
|
211
|
+
debuglevel=1
|
212
|
+
reposdir=/dev/null
|
213
|
+
logfile=/var/log/yum.log
|
214
|
+
retries=20
|
215
|
+
obsoletes=1
|
216
|
+
gpgcheck=0
|
217
|
+
assumeyes=1
|
218
|
+
syslog_ident=pandler
|
219
|
+
syslog_device=
|
220
|
+
plugins=0
|
221
|
+
|
222
|
+
[pandler]
|
223
|
+
name=Pandler
|
224
|
+
enabled=1
|
225
|
+
baseurl=#{yumrepo}
|
226
|
+
EOF
|
227
|
+
content
|
228
|
+
end
|
229
|
+
end
|